吐血整理如何在Google Earth Engine上写循环 五个代码实例详细拆解 您所在的位置:网站首页 current assets 怎么算 吐血整理如何在Google Earth Engine上写循环 五个代码实例详细拆解

吐血整理如何在Google Earth Engine上写循环 五个代码实例详细拆解

2023-04-10 00:44| 来源: 网络整理| 查看: 265

全文共计3万余字,涉及大量学科概念和技术细节,阅读压力较大。建议GEE初学者分配整块的时间来阅读,不推荐采用碎片化阅读的方式。

另外,鉴于文章篇幅过长,还是希望点进来的观众在把它扔进收藏夹吃灰之前,能先帮我点个赞。以往文章和回答往往收藏数两倍于点赞数,给我看傻了。

引言

写这篇文章填一下先前挖的坑。我曾在1年前说要写一篇关于 GEE 上.map()和.iterate()函数的技术贴。拖更这么久实在惭愧惭愧。

首先解答一个疑问,为什么需要自己写循环?确实,GEE 为各种数据类型提供了无数常用的内置函数,对这些方法做排列组合足以应对大多数使用场景,算法效率也颇佳。在有内置函数的情况下,我永远推荐内置函数。

然而,对策赶不上需求,总有时候需要部署个性化的算法。举个例子,数据聚合问题:现有一个小时级的气温数据集 hourlyTemp_imgcol,每小时整点提供一张近地表气温图像,要求借此生成一个每日平均均气温数据集 dailyTemp_imgcol,每天提供一张日均近地表气温图像。那么,GEE 有没有这样的内置函数:

var dailyTemp_imgcol = hourlyTemp_imgcol.aggregate('daily');

让我们一行代码出结果呢?没有。

以上的例子是细分学科下的任务,听起来还是挺稀罕的。那我就再举一个编程初学者一定会接触的算法,数列递推:由一个初始值按照一定的递推公式,生成一个固定长度的列表。GEE有没有类似这样的递推函数:

var List = Number.RECURSIVE_SEQUENCE(function, list_length);

来一步到位实现这个简单任务呢?很遗憾,也是没有的。

因此,尽管 GEE 内置函数库丰富,学会自己部署循环仍然很有必要。这是跨过初学者阶段、独立开展项目的必经之路。

在第一个例子中,我们需要按时间循环,每个日期计算一幅平均气温图像。在第二个例子中,我们需要按列表索引位置循环,每个索引位置上计算一个递推值。

第一个例子代表了一类问题,处理函数作用在每个元素上,让每个元素被映射到一个新的东西上,这样的话一定是多个输入和多个输出,并且有一一对应的关系。关于这种循环,我们使用.map()操作来处理,请阅读本文第(一)节。

第二个例子代表了另一类问题,处理函数的任务是产生累积的效果,后面步骤的执行会依赖前面步骤的产出。关于这一种循环,我们使用.iterate()操作来处理,请阅读本文第(二)节。

有些初学者会说,哪里需要那么麻烦,我以不变应万变,老师教的for循环就是无脑易上手,再说GEE又不是不支持。我想说,这种习惯在技术上确实可行,但是如果是放在 GEE 上部署,会严重拖慢计算效率。在展示如何写 GEE 式循环之前,我专门开一个第(〇)节,探讨一下这个问题。非常建议初学者阅读,会帮助你更好地理解,GEE 如何处理用户提交的任务。

然而并不是说任何情况都不能使用for循环。 有些情况下,因为.map()和.iterate()的技术限制,循环必须在本地端进行。我会举一下这种应用场景的例子,放在第(三)节。

让我们开始吧。

(〇) 为什么GEE不推荐for、while循环?

GEE 常被描述为“地理云计算平台”。那么,之所以被称为云计算,就是因为操作和计算是在服务器上发生的,而不是在自己的电脑(本地)上完成的。向服务器告知计算任务时所用的“语言”,称为API。目前已有JavaScript API(即Code Editor)、Python API、Julia API。

- 那么老哥,for和while是跟GEE服务器对话的语言吗?

- 不是。

- 难道说GEE服务器不看for语句?

- 它不看。

- 唉不对啊,我明明在Code Editor上面写了for循环却还能运行的,你说服务器不看for,难不成还能是浏览器给我跑的?

- 恭喜你答对了,还真是浏览器给跑的。

要解释这个问题,需要对GEE的工作机制有一个大概的了解。

作为小白,我们在Code Editor上写出几行代码并点击Run的一刻,可能很少想过这之后发生了什么。实际上,你的代码其实并不是直接抄一份送给服务器去读,而是要先在本地端浏览器上去做解析,重写成一套服务器听得懂的请求,然后才把请求送上去。

本地翻译的过程,在于解析每一个由用户声明的变量,把它们各自整理成一套能指导服务器算出结果的结构——你可以理解成是每一个云端对象在本地端的代理,是影子。它们会跟云端的、承载实际数据和计算的对象相对应。

在《Deferred Execution(延迟运行)》的页面上[1],谷歌解释了这一本地解析的过程:

When you write a script in Earth Engine (either JavaScript or Python), that code does NOT run directly on Earth Engine servers at Google. Instead, the client library encodes the script into a set of JSON objects, sends the objects to Google and waits for a response. Each object represents a set of operations required to get a particular output, an image to display in the client, for example.当您在Earth Engine上编写脚本时(无论JavaScript还是Python),该代码不会直接在谷歌的Earth Engine服务器上运行。相反,客户端库将脚本编码为一组JSON对象,将对象发送给谷歌并等待响应。每个对象表示获得特定输出所需的一组操作,例如,要在客户端上显示的图像。

进一步解释一下:代码写好之后,只会在本地做解析。本地端解析之后,会生成一些JSON对象。这些JSON对象是做什么用的呢?是客户端写给服务器的字条:“如此如此算一遍,把结果发给我。”

由此可以看出,本地端解析代码所能做的,只是解析代码,帮服务器提前理解该怎么做事而已,不涉及任何实际数据。它编写的JSON文件,只是云端数据在本地端的影子。生成这个影子的目的,或者说这个影子里所容纳的信息,就是指挥Google服务器以某某运算组合依次操作那个云端上的对象。

这样就解释了为什么for循环只在本地端有意义。我们在for循环里写的一切,是一种过程而不是一种对象,只会平添本地端的解析负担。for循环对服务器上计算过程产生影响之前,是要本地客户端来徒手拆循环的。

说句题外话,这其实很像在编纂纪传体史书。历史的原始记录就像我们写的代码一样,关注的是事情从头到尾怎么进行,是一种过程。而纪传体史书则关注主要人物个体如何发展,这更像GEE服务器的关注点,是一种对象。把流水账般的事项记录(过程),编制成人物个体的发展历程(对象及其操作顺序),并对互相影响的人物各自立传、一起成书,这些就是史官(和GEE API)的工作。

理解了本地端和服务器端对象的区别和联系,让我们再来讨论以for为代表的本地端循环,为什么不被推荐。

举个例子,我们这里有一个重复1万次的for循环,里面的内容是让一个ee.Number(服务器端的数)每次加 i:

// 语法没错但跑不通的例子,只是因为用了 for 循环 var num = ee.Number(0); for (var i=1; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有